home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Toolbox / GridWindowGrow / GrowToGrid.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-08  |  27.0 KB  |  810 lines  |  [TEXT/MPS ]

  1. /* simple example of creating a gridded window grow routine */
  2. /* to allow you to only let someone grow a window in increments */
  3. /* of 20 pixels, for example */
  4.  
  5. /* Look at the routine  MyGrowWindow  for the how-to*/
  6. /* C.K. Haun */
  7. /* Apple DTS */
  8. /* 8/4/94 */
  9.  
  10. #include <Types.h>
  11. #include <memory.h>
  12. #include <Packages.h>
  13. #include <Errors.h>
  14. #include <quickdraw.h>
  15. #include <fonts.h>
  16. #include <dialogs.h>
  17. #include <windows.h>
  18. #include <menus.h>
  19. #include <events.h>
  20. #include <OSEvents.h>
  21. #include <Desk.h>
  22. #include <diskinit.h>
  23. #include <OSUtils.h>
  24. #include <resources.h>
  25. #include <toolutils.h>
  26. #include <AppleEvents.h>
  27. #include <EPPC.h>
  28. #include <GestaltEqu.h>
  29. #include <PPCToolbox.h> 
  30. #include <Processes.h>
  31. #include <Balloons.h>
  32. #include <Aliases.h>
  33. #include <Aliases.h>
  34.  
  35. #define kExtremeNeg -32768
  36. #define kExtremePos (32767 - 1) /* required to address an old region bug, see develop 20 Q&As */
  37.  
  38. /* prototypes */
  39. void    DrawIndString(short resID,short index);
  40. void MyGrowWindow(WindowPtr theWindow);
  41. void InitalizeApp(void);
  42. void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
  43. void DrawMain(WindowPtr drawIt);
  44. Boolean DoSelected(long val);
  45. void SizeMain(WindowPtr theWindow);
  46. void InitAEStuff(void);
  47. void DoHighLevel(EventRecord *AERecord);
  48. void DoDaCall(MenuHandle themenu, long theit);
  49. void DoDocumentClick(WindowPtr theWindow);
  50. void DoGridDialog(void);
  51. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
  52. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  53. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  54. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  55. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  56. void SampleHelpDialog(void);
  57. WindowPtr AddNewWindow(short theID);
  58. WindowPtr FindWindowByKind(short kindToFind);
  59.  
  60. void NilProc(void);
  61.  
  62. /* one external */
  63. extern void _DataInit();                                    /* this is the C initialization code */
  64.  
  65. /* defines and enums */
  66. /* windows */
  67. enum  {
  68.     kDocumentWindow = 1000, kDocWindow = 128
  69. };
  70. /* menu enums */
  71. enum  {
  72.     kMBarID = 128, kAppleMenu = 128, kFileMenu = 129, kEditMenu = 130, kToolsMenu = 131
  73. };
  74. enum  {
  75.     kResumeMask = 1,                                        /* bit of message field for resume vs. suspend */
  76.     kHelpString = 128
  77. };
  78. /* file menu enums */
  79. enum  {
  80.     kNewItem = 1, kOpenItem, kCloseItem, kSaveItem, kSaveAsItem, kFileBlank1, kPageSetupItem, kPrintItem, kFileBlank2, kQuitItem
  81. };
  82.  
  83. enum  {
  84.     kGridDialogItem = 1
  85. };
  86.  
  87. /* alerts and dialogs */
  88.  
  89. enum  {
  90.     kBadSystem = 130, kSampHelp = 129, kAboutBox = 128, kGridDialog = 131
  91. };
  92.  
  93. enum  {
  94.     kGridDialogMenuItem = 1, kGridEditLine = 4
  95. };
  96.  
  97. enum  {
  98.     kMinHeight = 200
  99. };
  100.  
  101. enum {kGenStrings = 128,kSayCurrentGrid=1,kSayChangeGrid
  102. };
  103.  
  104. #define ABS(A) ((A < 0) ? (A*-1):A)
  105.  
  106. /* structs */
  107. struct AEinstalls {
  108.     AEEventClass theClass;
  109.     AEEventID theEvent;
  110.     AEEventHandlerUPP theProc;
  111. };
  112. typedef struct AEinstalls AEinstalls;
  113.  
  114.  
  115. /* windowControl is the structure attached to every window I create (in the refCon */
  116. /* field) that contains all the information I need to know about the window. */
  117. /* this one is really simple */
  118. struct windowControl {
  119.     unsigned long windowID;                                 /* master ID number for section recording */
  120.     ProcPtr drawMe;                                         /* content drawing procedure pointer */
  121.     ProcPtr clickMe;                                        /* content click routine */
  122.     ProcPtr saveMe;                                         /* document save procedure pointer */
  123.     ProcPtr closeMe;                                        /* document close procedure pointer */
  124.     ProcPtr sizeMe;
  125.     AliasHandle fileAliasHandle;                            /* alias for this document */
  126.     Boolean windowDirty;
  127.     long windowIndex;                                       /* for AppleEvent information */
  128.     
  129. };
  130. typedef struct windowControl windowControl, *windowCPtr, **windowCHandle;
  131.  
  132. /* globals */
  133. Boolean gQuit, gInBackground;
  134. Boolean dragIn;
  135. EventRecord gERecord;
  136. ProcessSerialNumber gOurSN;
  137. short gHelpItem;
  138. short gGridIncrement = 30;                                  // start at 30
  139.  
  140. #pragma segment Main
  141. main()
  142. {
  143.     
  144.     WindowPtr twindow;
  145.     short fHit;
  146.     windowCHandle tempWCH;
  147.         
  148.     UnloadSeg((Ptr)_DataInit);                              /* throw out C setup code */
  149.     InitalizeApp();
  150.     UnloadSeg((Ptr)InitalizeApp);                           /* get rid of my initialization code */
  151.     /* start running */
  152.     do {
  153.     
  154.         WaitNextEvent(everyEvent, &gERecord, 30, nil);
  155.     
  156.         switch (gERecord.what) {
  157.  
  158.             case nullEvent:
  159.                 /* no nul processing in this sample */
  160.                 break;
  161.  
  162.             case updateEvt:
  163.                 /* at update, draw the window */
  164.                 tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
  165.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
  166.                 
  167.                 break;
  168.                 
  169.             case mouseDown:
  170.                 /* first see where the hit was */
  171.                 fHit = FindWindow(gERecord.where, &twindow);
  172.                 
  173.                 switch (fHit) {
  174.  
  175.                     case inDesk:                            /* if they hit in desk, then the process manager */
  176.                         break;                              /* will switch us out, we don't need to do anything */
  177.  
  178.                     case inMenuBar:
  179.                         DoSelected(MenuSelect(gERecord.where));
  180.                         break;
  181.                         
  182.                     case inSysWindow:
  183.                         /* pass to the system */
  184.                         SystemClick(&gERecord, twindow);
  185.                         break;
  186.  
  187.                     case inContent:
  188.                         /* Handle content and control clicks here */
  189.                         if (FrontWindow()) {                /* don't do this unless we have a window open, silly */
  190.                             windowCHandle clicker;
  191.                             clicker = (windowCHandle)GetWRefCon(twindow);
  192.                             /* jump to the content function stored for this window */
  193.                             HLock((Handle)clicker);         /* lock it down so things don't get stupid */
  194.                             (ProcPtr)((*clicker)->clickMe)(twindow);
  195.                             HUnlock((Handle)clicker);       /* all done */
  196.                         }
  197.                         break;
  198.  
  199.                     case inDrag:
  200.                         if (twindow == FrontWindow())
  201.                             DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
  202.                         break;
  203.  
  204.                     case inGrow:
  205.                         /* Call GrowWindow here if you have a grow box */
  206.                         SetPort(twindow);
  207.                         MyGrowWindow(twindow);
  208.                         break;
  209.  
  210.                     case inGoAway:
  211.                         /* Click in Close box */
  212.                         if (TrackGoAway(twindow, gERecord.where))
  213.                             (ProcPtr)((*(windowCHandle)((WindowPeek)twindow)->refCon)->closeMe)(twindow);
  214.                         
  215.                         break;
  216.  
  217.                     case inZoomIn:
  218.                     case inZoomOut:
  219.                         if (TrackBox(twindow, gERecord.where, fHit)) {
  220.                             windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
  221.                             SetPort(twindow);
  222.                             
  223.                             ZoomWindow(twindow, fHit, true);
  224.                             InvalRect(&twindow->portRect);
  225.                             (ProcPtr)((*tempWCH)->sizeMe)(twindow);
  226.                         }
  227.                 } /* end mouseDown case */
  228.  
  229.             case mouseUp:
  230.                 /* don't care */
  231.                 break;
  232.  
  233.                 /* same action for key or auto key */
  234.             case keyDown:
  235.             case autoKey:
  236.                 if (gERecord.modifiers & cmdKey)
  237.                     DoSelected(MenuKey(gERecord.message & charCodeMask));
  238.                 break;
  239.  
  240.             case keyUp:
  241.                 /* don't care */
  242.                 break;
  243.  
  244.             case diskEvt:
  245.                 /* I don't do anything special for disk events, this just passes them */
  246.                 /* to a function that checks for an error on the mount */
  247.                 DoDiskEvents(gERecord.message);
  248.                 break;
  249.  
  250.             case activateEvt:
  251.                 if (gERecord.modifiers & activeFlag) {
  252.                     tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
  253.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
  254.                 }
  255.                 break;
  256.  
  257.             case networkEvt:
  258.                 /* don't care */
  259.                 break;
  260.  
  261.             case driverEvt:
  262.                 /* don't care */
  263.                 break;
  264.  
  265.             case app4Evt:
  266.                 switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  267.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  268.                         gInBackground = (gERecord.message & kResumeMask) == 0;
  269.                         break;
  270.                 }
  271.                 break;
  272.  
  273.                 /* This dispatches high level events (AppleEvents, for example) */
  274.                 /* to our dispatch routine. This is NEW in the event loop for */
  275.                 /* System 7 */
  276.             case kHighLevelEvent:
  277.                 DoHighLevel(&gERecord);
  278.                 break;
  279.  
  280.             default:
  281.                 break;
  282.                 
  283.         }
  284.     }while (gQuit != true);
  285.     
  286. }
  287.  
  288. /* DoDaCall opens the requested DA. It's here as a seperate routine if you'd */
  289. /* like to perform some action or just know when a DA is opened in your */
  290. /* layer. Can be handy to track memory problems when a DA is opened */
  291. /* with an Option-open */
  292. void DoDaCall(MenuHandle themenu, long theit)
  293. {
  294.     long qq;
  295.     char DAname[255];
  296.     GetItem(themenu, theit, &DAname);
  297.     qq = OpenDeskAcc(DAname);
  298. }
  299.  
  300. /* end DoDaCall */
  301.  
  302. /* DoDiskEvents just checks the error code from the disk mount, */
  303. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  304. /* You can do much more here if you care about what disks are */
  305. /* in the drive */
  306. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  307. {
  308.     short hival, loval, tommy;
  309.     Point fredpoint =  {
  310.         40, 40
  311.     };
  312.     hival = HiWord(dinfo);
  313.     loval = LoWord(dinfo);
  314.     if (hival != noErr)                                     /* something happened */ {
  315.         tommy = DIBadMount(fredpoint, dinfo);
  316.     }
  317. }
  318.  
  319. /* draws my window. Pretty simple */
  320. void DrawMain(WindowPtr drawIt)
  321. {
  322.     RgnHandle tempRgn;
  323.     Rect scratchRect;
  324.     Str31 tempString;
  325.     BeginUpdate(drawIt);
  326.     SetPort(drawIt);
  327.     EraseRect(&drawIt->portRect);
  328.     MoveTo(10, 17);
  329.     DrawIndString(kGenStrings,kSayCurrentGrid);
  330.     NumToString(gGridIncrement, &tempString);
  331.     DrawString(tempString);
  332.     MoveTo(10, 37);
  333.     DrawIndString(kGenStrings,kSayChangeGrid);
  334.     
  335.     scratchRect = drawIt->portRect;
  336.     scratchRect.top = scratchRect.bottom - 15;
  337.     scratchRect.left = scratchRect.right - 15;
  338.     tempRgn = NewRgn();
  339.     GetClip(tempRgn);
  340.     ClipRect(&scratchRect);
  341.     DrawGrowIcon(drawIt);
  342.     SetClip(tempRgn);
  343.     DisposeRgn(tempRgn);
  344.     
  345.     EndUpdate(drawIt);
  346. }
  347.  
  348. /* my menu action taker. It returns a Boolean which I usually ignore, but it */
  349. /* mught be handy someday */
  350. Boolean DoSelected(long val)
  351. {
  352.     short loval, hival;
  353.     Boolean returnVal = false;
  354.     loval = LoWord(val);
  355.     hival = HiWord(val);
  356.     
  357.     switch (hival) {                                        /* switch off the menu number selected */
  358.         case kAppleMenu:                                    /* Apple menu */
  359.             if (loval != 1) {                               /* if this was not About, it's a DA */
  360.                 DoDaCall(GetMHandle(kAppleMenu), loval);
  361.             } else {
  362.                 Alert(kAboutBox, nil);                      /* do about box */
  363.             }
  364.             returnVal = true;
  365.             break;
  366.         case kFileMenu:                                     /* File menu */
  367.             switch (loval) {
  368.                 case kQuitItem:
  369.                     gQuit = true;                           /* only item */
  370.                     returnVal = true;
  371.                     break;
  372.                 default:
  373.                     break;
  374.             }
  375.             break;
  376.         case kEditMenu:
  377.             /* edit menu junk */
  378.             /* don't care */
  379.             break;
  380.         case kToolsMenu:
  381.         case kGridDialogItem:
  382.             DoGridDialog();
  383.             break;
  384.             break;
  385.         case kHMHelpMenuID:                                 /* Defined in Balloons.h */
  386.             /* I only care about this item. If anything else is returned here, I don't know what */
  387.             /* it is, so I leave it alone. Remember, the Help Manager chapter says that */
  388.             /* Apple reserves the right to add and change things in the Help menu */
  389.             if (loval == gHelpItem)
  390.                 SampleHelpDialog();
  391.             break;
  392.             
  393.     }
  394.     HiliteMenu(0);
  395.     return(returnVal);
  396. }
  397.  
  398. void DoDocumentClick(WindowPtr theWindow)
  399. {
  400. #pragma unused (theWindow )
  401. }
  402.  
  403. /* InitAEStuff installs my appleevent handlers */
  404. void InitAEStuff(void)
  405. {
  406.     static AEinstalls HandlersToInstall[] =  { {
  407.             kCoreEventClass, kAEOpenApplication, AEOpenHandler
  408.         },  {
  409.             kCoreEventClass, kAEOpenDocuments, AEOpenDocHandler
  410.         },  {
  411.             kCoreEventClass, kAEQuitApplication, AEQuitHandler
  412.         },  {
  413.             kCoreEventClass, kAEPrintDocuments, AEPrintHandler
  414.         }, 
  415.         /* The above are the four required AppleEvents. */
  416.         
  417.     };
  418.     
  419.     OSErr aevtErr = noErr;
  420.     long aLong = 0;
  421.     Boolean gHasAppleEvents = false;
  422.     /* Check this machine for AppleEvents. If they are not here (ie not 7.0)
  423.     * then we exit */
  424.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  425.     /* The following series of calls installs all our AppleEvent Handlers.
  426.     * These handlers are added to the application event handler list that 
  427.     * the AppleEvent manager maintains. So, whenever an AppleEvent happens
  428.     * and we call AEProcessEvent, the AppleEvent manager will check our
  429.     * list of handlers and dispatch to it if there is one.
  430.     */
  431.     if (gHasAppleEvents) {
  432.         register qq;
  433.         for (qq = 0; qq < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); qq++) {
  434.             aevtErr = AEInstallEventHandler(HandlersToInstall[qq].theClass, HandlersToInstall[qq].theEvent,
  435.                                             HandlersToInstall[qq].theProc, 0, false);
  436.             if (aevtErr) {
  437.                 ExitToShell();                              /* just fail, baby */
  438.             }
  439.         }
  440.     } else {
  441.         ExitToShell();
  442.     }
  443. }
  444.  
  445. /* end InitAEStuff */
  446. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  447. /* easy for me to say, huh? */
  448. void DoHighLevel(EventRecord *AERecord)
  449. {
  450.     
  451.     AEProcessAppleEvent(AERecord);
  452.     
  453. }
  454.  
  455. /* end DoHighLevel */
  456.  
  457. /* This is the standard Open Application event. */
  458. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  459. {
  460. #pragma unused (messagein,reply,refIn)
  461.     /* we of course don't do anything here in this simple app */
  462.     /* except open our window */
  463.     AddNewWindow(128);
  464.     return(noErr);
  465. }
  466.  
  467. /* end AEOpenHandler */
  468.  
  469. /* Open Doc, opens our documents. Remember, this can happen at application start AND */
  470. /* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
  471. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  472. /* handler will get called. Which means you don't do any initialization of globals here, or */
  473. /* anything else except open then doc. */
  474. /* SO-- Do NOT assume that you are at app start time in this */
  475. /* routine, or bad things will surely happen to you. */
  476.  
  477. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  478. {
  479. #pragma unused (messagein,refIn,reply)
  480.     /* we of course don't do anything here */
  481.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  482. }
  483.  
  484. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  485. {                                                           /* no printing handler in yet, so we'll ignore this */
  486.     /* the operation is functionally identical to the ODOC event, with the additon */
  487.     /* of calling your print routine. */
  488. #pragma unused (messagein,refIn,reply)
  489.     /* we of course don't do anything here */
  490.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  491. }
  492.  
  493. /* Standard Quit event handler, to handle a Quit event from the Finder, for example. */
  494. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life. */
  495. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  496. {
  497. #pragma unused (messagein,refIn,reply)
  498.     
  499.     /* prepQuit sets the Stop flag for us. It does _NOT_ quit, you */
  500.     /* should NEVER quit from an AppleEvent handler. Calling */
  501.     /* ExitToShell here would blow things up */
  502.     gQuit = true;
  503.     return(noErr);
  504. }
  505.  
  506. /* This is my sample help dialog. Does not do anything, expand as you need */
  507. void SampleHelpDialog(void)
  508. {
  509.     DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1);
  510.     short itemhit = 0;
  511.     while (itemhit != 1) {
  512.         ModalDialog((ModalFilterProcPtr)nil, &itemhit);
  513.     }
  514.     DisposDialog(tdial);
  515. }
  516.  
  517.  
  518. #pragma segment Initialize
  519. void InitalizeApp(void)
  520. {
  521.     MenuHandle helpHandle;
  522.     Handle myMenuBar;
  523.     StringHandle helpString;
  524.     short count;
  525.     long vers;
  526.     MaxApplZone();
  527.     InitGraf((Ptr)&qd.thePort);
  528.     InitFonts();
  529.     InitWindows();
  530.     InitMenus();
  531.     TEInit();
  532.     InitDialogs(nil);
  533.     InitCursor();
  534.     /* Check system version */
  535.     Gestalt(gestaltSystemVersion, &vers);
  536.     vers = (vers >> 8) & 0xf;                               /* shift result over and mask out major version number */
  537.     if (vers < 7) {
  538.         StopAlert(kBadSystem, nil);
  539.         ExitToShell();
  540.     }
  541.     InitAEStuff();
  542.     /* set up my menu junk */
  543.     myMenuBar = GetNewMBar(kMBarID);
  544.     SetMenuBar(myMenuBar);
  545.     AddResMenu(GetMHandle(kAppleMenu), 'DRVR');
  546.     /* now install my Help menu item in the Help Manager's menu */
  547.     HMGetHelpMenuHandle(&helpHandle);                       /* Get the Hlpe menu handle */
  548.     count = CountMItems(helpHandle);                        /* How many items are there? */
  549.     helpString = GetString(kHelpString);                    /* get my help string */
  550.     DetachResource(helpString);                             /* detach it */
  551.     HNoPurge(helpString);
  552.     MoveHHi((Handle)helpString);
  553.     HLock((Handle)helpString);
  554.     InsMenuItem(helpHandle, (Ptr)*helpString, count + 1);       /* insert my item in the Help menu */
  555.     gHelpItem = CountMItems(helpHandle);                    /* The number of the item */
  556.     
  557.     DrawMenuBar();
  558.     GetCurrentProcess(&gOurSN);                             /* Get our process serial number for later use, if needed */
  559.     
  560. }
  561.  
  562.  
  563. #pragma segment Main
  564. WindowPtr AddNewWindow(short theID)
  565. {
  566.     windowCHandle setControls;
  567.     WindowPtr tempWP;
  568.     short cnt = 0;
  569.     tempWP = GetNewWindow(theID, 0, (WindowPtr)-1);         /* get a new window */
  570.     SetPort(tempWP);
  571.     ((WindowPeek)tempWP)->windowKind = kDocumentWindow;     /* mark it as a document window */
  572.     setControls = (windowCHandle)NewHandleClear(sizeof(windowControl));     /* add our control structure to it */
  573.     SetWRefCon(tempWP, (long)setControls);                  /* stop stuffing refCon directly <ckh 1.0.3> */
  574.     HLock((Handle)setControls);                             /* lock it down while we fill it*/
  575.     
  576.     /* add pointers to our procedures for drawing, saving, and closing */
  577.     /* This way, all I need is one dispatch point for drawing, closing */
  578.     /* or whatever, I don't have to case off the window kind to go to the */
  579.     /* correct routine. Kinda like object-oriented programming, but I won't */
  580.     /* admit that. */
  581.     (*setControls)->drawMe = (ProcPtr)DrawMain;
  582.     (*setControls)->saveMe = (ProcPtr)NilProc;
  583.     (*setControls)->closeMe = (ProcPtr)NilProc;
  584.     (*setControls)->clickMe = (ProcPtr)DoDocumentClick;
  585.     (*setControls)->sizeMe = (ProcPtr)SizeMain;
  586.     /* now initialize all our required handles */
  587.     return(tempWP);
  588. }
  589.  
  590. void SizeMain(WindowPtr theWindow)
  591. {
  592.     WindowPtr tempWP;
  593.     GetPort(&tempWP);
  594.     InvalRect(&theWindow->portRect);
  595.     SetPort(tempWP);
  596. }
  597.  
  598. void NilProc(void)
  599. {
  600.     
  601. }
  602.  
  603. // This will grid a window grow to a specific increment
  604.  
  605. void PullRect(Rect *startRect)
  606. {
  607.     
  608.     Rect oldRect;
  609.     Point endPoint;
  610.     Boolean hreversed = false;
  611.     Boolean vreversed = false;
  612.     short tempH, tempV;
  613.     short divBy20h, divBy20v;
  614.     /* set up */
  615.     oldRect = *startRect;
  616.     PenMode(srcXor);                                        /* So we can rubberband */
  617.     PenPat(&qd.gray);
  618.     FrameRect(startRect);
  619.     divBy20h = startRect->right;
  620.     divBy20v = startRect->bottom;
  621.     
  622.     
  623.     while (StillDown()) {                                   /* Keep doing this as long as the */
  624.         
  625.         /* user keeps the mouse down */
  626.         GetMouse(&endPoint);                                /* Current mouse position in local */
  627.         // see if it's on a  grid point
  628.         
  629.         tempH = ABS(endPoint.h - divBy20h) / gGridIncrement;
  630.         tempV = ABS(endPoint.v - divBy20v) / gGridIncrement;
  631.         // normalize to our grid values. We'll always go outwards as better
  632.         if ((tempH * gGridIncrement) != ABS(endPoint.h - divBy20h)) {
  633.             // shove out based on the remainer
  634.             endPoint.h = (((endPoint.h)/gGridIncrement)*gGridIncrement)+gGridIncrement;
  635.         }
  636.         if ((tempV * gGridIncrement) != ABS(endPoint.v - divBy20v)) {
  637.             endPoint.v = (((endPoint.v)/gGridIncrement)*gGridIncrement)+gGridIncrement;
  638.             
  639.         }
  640. // If things reversed, we have to make sure that we don't try
  641. // and grid the origin point of the drag, cuz that would be weird
  642.  
  643.             if (hreversed) {
  644.                 /* see if the rectangle flipped first */
  645.                 if (endPoint.h > startRect->right) {
  646.                     /* they flipped back */
  647.                     hreversed = false;                      /* and ignore this move */
  648.                 } else {
  649.                     /* still reversed */
  650.                     startRect->left = endPoint.h;
  651.                 }
  652.             } else {
  653.                 if (endPoint.h < startRect->left) {
  654.                     hreversed = true;
  655.  
  656.                 } else {
  657.                     startRect->right = endPoint.h;
  658.                 }
  659.             }
  660.             if (vreversed) {
  661.                 /* see if it flipped first */
  662.                 if (endPoint.v > startRect->bottom) {
  663.                     /* they flipped back */
  664.                     vreversed = false;                      /* and ignore this move */
  665.                 } else {
  666.                     /* still reversed */
  667.                     startRect->top = endPoint.v;
  668.                 }
  669.             } else {
  670.                 if (endPoint.v < startRect->top) {
  671.                     vreversed = true;
  672.                 } else {
  673.                     startRect->bottom = endPoint.v;
  674.                 }
  675.             }
  676.             if (*startRect != oldRect) {                    /* redraw the rect only if the mouse moved */
  677.                 FrameRect(&oldRect);
  678.                 FrameRect(startRect);                       /* draw the new rect */
  679.                 oldRect = *startRect;
  680.             }
  681.         
  682.     }    
  683.     FrameRect(startRect);
  684.     
  685.     PenMode(srcCopy);
  686.     PenPat(&qd.black);
  687. }
  688.  
  689. void MyGrowWindow(WindowPtr theWindow)
  690. {
  691.     PenState oldPen;
  692.     WindowPtr tempWP, WMPort;
  693.     Rect draggingRect = theWindow->portRect;
  694.     Rect wideOpen =  {
  695.         kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos
  696.     };
  697.     RgnHandle oldRgn = NewRgn();
  698.     
  699.     GetPort(&tempWP);
  700.     SetPort(theWindow);
  701.     /* normalize my rectangle into the window manager port coordinates */
  702.     LocalToGlobal((Point *)&draggingRect);
  703.     LocalToGlobal((Point *)&draggingRect.bottom);
  704.     /*  go to the WManager port */
  705.     GetWMgrPort(&WMPort);
  706.     SetPort(WMPort);
  707.     /* save the Window manager pen state since we'll be changing it */
  708.     GetPenState(&oldPen);
  709.     /* localize back */
  710.     GlobalToLocal((Point *)&draggingRect);
  711.     GlobalToLocal((Point *)&draggingRect.bottom);
  712.     
  713.     /* save the current clip region, and set our wide-open clip */
  714.     GetClip(oldRgn);
  715.     ClipRect(&wideOpen);
  716.     /* go to the routine above and do the actual dragging */
  717.     PullRect(&draggingRect);
  718.     
  719.     /* restore the original environment */
  720.     SetClip(oldRgn);
  721.     SetPenState(&oldPen);
  722.     DisposeRgn(oldRgn);
  723.     /* now size the window for the returned rect */
  724.     SetPort(theWindow);
  725.     InvalRect(&theWindow->portRect);
  726.     SizeWindow(theWindow, draggingRect.right - draggingRect.left, draggingRect.bottom - draggingRect.top, true);
  727.     SetPort(tempWP);
  728.     
  729. }
  730.  
  731.  
  732. void DoGridDialog(void)
  733. {
  734.     Str255 tempString;
  735.     WindowPtr tempWP=nil;
  736.     WindowPtr tempPort=nil;
  737.  
  738.     long aLong;
  739.     DialogPtr theDialog = GetNewDialog(kGridDialog, nil, (WindowPtr)-1);
  740.     short itemHit = 0;
  741.     ModalFilterUPP theStdProc=nil;   // inited to nil in case the Get fails
  742.  
  743.     // get some automatic dialog behaviour 
  744.     SetDialogDefaultItem(theDialog,ok);
  745.     SetDialogTracksCursor(theDialog,true);
  746.     GetStdFilterProc(&theStdProc);
  747.  
  748.     // set the item to be the current grid value
  749.  
  750.     NumToString(gGridIncrement, &tempString);
  751.     SetIText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
  752.     
  753.     // spin until they hit OK or Cancel
  754.     while (itemHit != ok && itemHit !=cancel) {
  755.         ModalDialog(theStdProc, &itemHit);
  756.     }
  757.     
  758.     if (itemHit == 1) {
  759.         // they OK'ed their new grid value
  760.         GetIText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
  761.         StringToNum(tempString, &aLong);
  762.         gGridIncrement = aLong;
  763.     // invalidate our document window so the new value will be refelcted
  764.     tempWP = FindWindowByKind(kDocumentWindow);
  765.     if(tempWP != nil){
  766.         GetPort(&tempPort);
  767.         SetPort(tempWP);
  768.         InvalRect(&tempWP->portRect);
  769.         SetPort(tempPort);
  770.     }
  771.     }
  772.     
  773.     DisposDialog(theDialog);
  774. }
  775.  
  776. /* gets a handle from a dialog item  */
  777. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  778. {
  779.     short itemtype;
  780.     Rect itemrect;
  781.     Handle thandle;
  782.     GetDItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  783.     return((ControlHandle)thandle);
  784. }
  785.  
  786. /* end SnatchHandle */
  787.  
  788. /* loads an index string and draws it.  Just a convinice */
  789. void    DrawIndString(short resID,short index)
  790. {
  791. Str255 theString;
  792. GetIndString(theString,resID,index);
  793. DrawString(theString);
  794. }
  795.  
  796. /* returns the first window of specified kind, or nil if none */
  797. WindowPtr FindWindowByKind(short kindToFind)
  798. {
  799. WindowPtr currentWindow = FrontWindow();
  800. while(currentWindow){
  801.     if(((WindowPeek)currentWindow)->windowKind == kindToFind){
  802.         // found it, break
  803.         break;
  804.     } else {
  805.         // go to the next one
  806.         currentWindow = (WindowPtr) ((WindowPeek)currentWindow)->nextWindow;
  807.     }
  808. }
  809. return ( currentWindow );
  810. }